
package com.epam.android.training.day11.task1;

import android.app.ListActivity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.MimeTypeMap;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

import java.io.File;
import java.io.FilenameFilter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
 * File picker activity that performs navigation on device file system and
 * allows to pick a file.
 * 
 * @author Anton Novikov
 */
public class FilePicker extends ListActivity {

  public static final String MIME_TYPE_EXTRA = "MIME_TYPE";

  public static final String FILE_PATH_EXTRA = "FILE_PATH";

  private static final String INITIAL_LOCATION = "/";

  private String filterMimeType;

  private File dir;

  private List<File> files;

  private ArrayAdapter<File> adapter;

  /** Called when the activity is starting. */
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    filterMimeType = getIntent().getStringExtra(MIME_TYPE_EXTRA);

    dir = new File(INITIAL_LOCATION);
    files = new ArrayList<File>();

    adapter = new FilePickerListAdapter(this, files);
    setListAdapter(adapter);
  }

  /**
   * Rebuild file navigator list to previous state until initial path. When
   * parent reaches initial location back to the previously launched activity.
   */
  @Override
  public void onBackPressed() {
    if (dir.getParentFile() != null && !INITIAL_LOCATION.equals(dir.getAbsolutePath())) {
      // Go to parent directory
      dir = dir.getParentFile();
      refreshFilesList();
      return;
    }

    super.onBackPressed();
  }

  /**
   * Performs step into selected directory or pick of selected file.
   */
  @Override
  protected void onListItemClick(ListView l, View v, int position, long id) {
    File newFile = (File) l.getItemAtPosition(position);

    if (newFile.isFile()) {
      // Set result
      Intent extra = new Intent();
      extra.putExtra(FILE_PATH_EXTRA, newFile.getAbsolutePath());
      setResult(RESULT_OK, extra);
      // Finish the activity
      finish();
    } else {
      dir = newFile;
      // Update the files list
      refreshFilesList();
    }

    super.onListItemClick(l, v, position, id);
  }

  /**
   * Rebuild file list on resume.
   */
  @Override
  protected void onResume() {
    refreshFilesList();
    super.onResume();
  }

  /**
   * Updates the list view to the current directory
   */
  private void refreshFilesList() {
    // Clear the files ArrayList
    files.clear();

    // Set the extension file filter
    MimeTypeFilter filter = new MimeTypeFilter(filterMimeType);

    // Get the files in the directory
    File[] files = dir.listFiles(filter);
    if (files != null && files.length > 0) {
      this.files.addAll(Arrays.asList(files));

      Collections.sort(this.files, new FileComparator());
    }
    adapter.notifyDataSetChanged();
  }

  /**
   * Adapter for file picker list view.
   * 
   * @author Anton Novikov
   */
  private class FilePickerListAdapter extends ArrayAdapter<File> {
    private final List<File> items;

    public FilePickerListAdapter(Context context, List<File> items) {
      super(context, R.layout.file_picker_item, android.R.id.text1, items);
      this.items = items;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
      View row = null;

      if (convertView == null) {
        LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(
            Context.LAYOUT_INFLATER_SERVICE);
        row = inflater.inflate(R.layout.file_picker_item, parent, false);
      } else {
        row = convertView;
      }

      File item = items.get(position);
      ImageView imageView = (ImageView) row.findViewById(R.id.file_icon);
      TextView textView = (TextView) row.findViewById(R.id.file_name);

      textView.setText(item.getName());
      if (item.isFile()) {
        // Show the file icon
        imageView.setImageResource(R.drawable.ic_file);
      } else {
        // Show the folder icon
        imageView.setImageResource(R.drawable.ic_folder);
      }
      return row;
    }
  }

  /**
   * Comparator to sort files and directories in file navigator.
   * 
   * @author Anton Novikov
   */
  private class FileComparator implements Comparator<File> {
    @Override
    public int compare(File f1, File f2) {
      if (f1 == f2) {
        return 0;
      }
      if (f1.isDirectory() && f2.isFile()) {
        // Show directories above files
        return -1;
      }
      if (f1.isFile() && f2.isDirectory()) {
        // Show files below directories
        return 1;
      }
      // Sort the directories alphabetically
      return f1.getName().compareToIgnoreCase(f2.getName());
    }
  }

  /**
   * File filter which filters children by specified MIME type.
   * 
   * @author Anton Novikov
   */
  private class MimeTypeFilter implements FilenameFilter {
    private final String mimeType;

    public MimeTypeFilter(String mimeType) {
      this.mimeType = (mimeType != null) ? mimeType : "*/*";
    }

    @Override
    public boolean accept(File dir, String filename) {
      if (new File(dir, filename).isDirectory()) {
        // Accept all directory names
        return true;
      }

      int extIndex = filename.lastIndexOf(".");
      if (extIndex > 0) {
        String ext = filename.substring(extIndex + 1);
        MimeTypeMap mimeTypeMap = MimeTypeMap.getSingleton();
        String type = mimeTypeMap.getMimeTypeFromExtension(ext);

        String mimeRegex = mimeType.replaceAll("\\*", ".+");
        if (type != null && type.matches(mimeRegex)) {
          return true;
        }
      }

      // if file doesn't matches any mime type or doesn't have appropriate
      // extension do not accept them.
      return false;
    }
  }
}
